/**
 * Yjs Worker：在后台线程进行增量合并、快照生成、状态编码，减轻主线程压力。
 *
 * 主线程使用场景与对接方：
 * - 与 IndexedDB 对接：
 *   - 启动时本地恢复：将 { snapshot, updates } 发给 build-doc，让 Worker 在后台构建最新 Doc；
 *   - 周期快照：发送 make-snapshot，Worker 返回全量更新包（可直接保存到 docs.snapshot）。
 * - 与 Socket Provider 对接（间接）：
 *   - 本地更新：apply-local-update（来源于 ydoc.on('update')）；
 *   - 远端/补齐更新：apply-remote-update（来源于 socket 'update' 或 'sync-step2'）；
 *   - 握手辅助：state-vector（在需要时获取最新 stateVector，用于 sync-step1）。
 *
 * 消息协议（主线程 -> Worker）：
 * - init: { documentId? }
 *   说明：初始化新的 Y.Doc 上下文，清理旧实例，防止不同文档串扰。
 *   返回：{ type:'inited' }
 *
 * - build-doc: { snapshot?:ArrayBuffer, updates?:ArrayBuffer[] }
 *   说明：在空 Doc 上依次应用 snapshot 与 updates 以重建最新状态。
 *   返回：{ type:'built', payload:{ stateVector:ArrayBuffer } }
 *          stateVector 用于 y-protocols sync-step1 握手。
 *
 * - apply-local-update: { update:ArrayBuffer }
 *   说明：应用“本地产生”的一次增量（ydoc.on('update') 的 payload）。
 *   返回：无（必要时可扩展为 { type:'applied' }）。
 *
 * - apply-remote-update: { update:ArrayBuffer }
 *   说明：应用“远端（或补齐）”更新（socket 'update'/'sync-step2' 的 payload）。
 *   返回：无。
 *
 * - apply-batch-updates: { updates:ArrayBuffer[] }
 *   说明：一次性批量应用多条更新（例如重连后本地补齐、或批量上行前的本地合并）。
 *   返回：无。
 *
 * - make-snapshot: {}
 *   说明：对当前 Doc 进行全量编码，返回一个“可以在空 Doc 上直接应用”的更新包。
 *   返回：{ type:'snapshot', payload:{ snapshot:ArrayBuffer } }
 *
 * - state-vector: {}
 *   说明：编码并返回当前 Doc 的 stateVector（用于 sync-step1）。
 *   返回：{ type:'state-vector', payload:{ stateVector:ArrayBuffer } }
 *
 * - state-update: {}
 *   说明：编码并返回当前 Doc 的完整状态（等价于 make-snapshot，命名别名，便于语义区分）。
 *   返回：{ type:'state-update', payload:{ update:ArrayBuffer } }
 *
 * - reset: {}
 *   说明：销毁当前 Doc 并创建一个新的空 Doc（不返回历史）。
 *   返回：{ type:'reset-done' }
 */
import * as Y from "yjs";

let doc: Y.Doc | null = null;
// Worker 的 doc只是后台合并/编码用的“影子文档”

function toU8(buf: ArrayBuffer | Uint8Array): Uint8Array {
  // 统一转为 Uint8Array，便于 Y.applyUpdate 消费
  return buf instanceof Uint8Array ? buf : new Uint8Array(buf);
}

self.onmessage = async (e: MessageEvent) => {
  const { type, payload } = (e.data || {}) as { type: string; payload?: any };
  switch (type) {
    case "init": {
      // 重新初始化 Doc（避免不同文档间状态串扰）
      // 入参：{ documentId?: string }（可选，仅做调试标识，不参与逻辑）
      // 对接：页面首次进入文档/切换文档时调用
      // 返回：{ type: 'inited' }
      doc?.destroy?.();
      doc = new Y.Doc();
      (self as any).postMessage({ type: "inited" });
      break;
    }

    case "build-doc": {
      // 基于快照与增量重建最新状态
      // 入参：{ snapshot?: ArrayBuffer, updates?: ArrayBuffer[] }
      // 顺序：先应用 snapshot（基线），再逐条应用 updates（补齐至最新）
      // 对接：IndexedDB 启动恢复；应用完成后即可从 Worker 拉取 stateVector 参与 sync-step1
      // 返回：{ type: 'built', payload: { stateVector: ArrayBuffer } }
      // 注意：入参与出参均走 transferable（ArrayBuffer）以避免拷贝
      doc?.destroy?.();
      doc = new Y.Doc();
      const { snapshot, updates } = payload || {};
      try {
        if (snapshot) Y.applyUpdate(doc, toU8(snapshot)); // 先应用基线快照

        for (const up of updates || []) Y.applyUpdate(doc, toU8(up)); // 再按序补齐增量

        const stateVector = Y.encodeStateVector(doc); // 返回 stateVector 便于握手
        // sync-step1

        // 返回 数据状态 向量
        (self as any).postMessage(
          { type: "built", payload: { stateVector: stateVector.buffer } },
          [stateVector.buffer]
        );

      } catch (err) {
        (self as any).postMessage({ type: "error", payload: { msg: "build-doc failed", err } });
      }
      break;
    }

    case "apply-local-update":
    case "apply-remote-update": {
      if (!doc) break;
      // 入参：{ update: ArrayBuffer }
      // 用途：将一条增量应用到 Doc。
      // - 本地增量：来自 ydoc.on('update') → apply-local-update
      // - 远端增量：来自 socket 'update' 或 'sync-step2' → apply-remote-update
      // 特性：Y.applyUpdate 幂等，可重复应用同一更新包而安全
      try {
        // 幂等应用增量，Yjs 内部可重复应用同一更新而安全
        Y.applyUpdate(doc, toU8(payload.update));
      } catch { }
      break;
    }

    case "apply-batch-updates": {
      if (!doc) break;
      // 入参：{ updates: ArrayBuffer[] }
      // 用途：批量应用多条更新，减少多次消息/调用带来的开销（重连补齐/导入等场景）
      // 要求：保持输入数组顺序，即为应用顺序
      try {
        const arr: ArrayBuffer[] = (payload?.updates as ArrayBuffer[]) || [];
        for (const up of arr) Y.applyUpdate(doc, toU8(up));
      } catch (err) {
        (self as any).postMessage({ type: "error", payload: { msg: "apply-batch-updates failed", err } });
      }
      break;
    }
    case "make-snapshot": {
      if (!doc) break;
      // 入参：无
      // 用途：对当前 Doc 进行全量编码（full-state update）
      // 对接：将返回值持久化到 IndexedDB.docs 表（字段 snapshot）
      // 返回：{ type: 'snapshot', payload: { snapshot: ArrayBuffer } }
      const snap = Y.encodeStateAsUpdate(doc);
      
      // 快照制作完后 发送 snapshot 消息 给主线程 返回快照
      (self as any).postMessage({ type: "snapshot", payload: { snapshot: snap.buffer } }, [snap.buffer]);
      break;
    }
    case "state-vector": {
      if (!doc) break;
      // 入参：无
      // 用途：编码当前 stateVector，用于 y-protocols sync-step1 握手
      // 返回：{ type: 'state-vector', payload: { stateVector: ArrayBuffer } }
      try {
        const v = Y.encodeStateVector(doc);
        (self as any).postMessage({ type: "state-vector", payload: { stateVector: v.buffer } }, [v.buffer]);
      } catch (err) {
        (self as any).postMessage({ type: "error", payload: { msg: "state-vector failed", err } });
      }
      break;
    }
    case "state-update": {
      if (!doc) break;
      // 入参：无
      // 用途：返回完整状态的更新包（等价于 make-snapshot，命名别名便于阅读）
      // 返回：{ type: 'state-update', payload: { update: ArrayBuffer } }
      try {
        const u = Y.encodeStateAsUpdate(doc);
        (self as any).postMessage({ type: "state-update", payload: { update: u.buffer } }, [u.buffer]);
      } catch (err) {
        (self as any).postMessage({ type: "error", payload: { msg: "state-update failed", err } });
      }
      break;
    }
    case "reset": {
      // 入参：无
      // 用途：销毁并重建空 Doc，常用于切换到新文档前的清理与复位
      // 返回：{ type: 'reset-done' }
      try { doc?.destroy?.(); } catch { }
      doc = new Y.Doc();
      (self as any).postMessage({ type: "reset-done" });
      break;
    }

    // 将 JSON 操作放到 Worker，减轻主线程负担
    case "json-stringify": {
      // 入参：{ data: any, jobId: number }
      // 返回：{ type: 'json-stringify-result', payload: { jobId:number, json:string } }
      try {
        const { data, jobId } = payload || {};
        const json = JSON.stringify(data);
        (self as any).postMessage({ type: "json-stringify-result", payload: { jobId, json } });
      } catch (err) {
        (self as any).postMessage({ type: "error", payload: { msg: "json-stringify failed", err } });
      }
      break;
    }
    case "json-parse": {
      // 入参：{ json: string, jobId: number }
      // 返回：{ type: 'json-parse-result', payload: { jobId:number, data:any } }
      try {
        const { json, jobId } = payload || {};
        const data = JSON.parse(json);
        (self as any).postMessage({ type: "json-parse-result", payload: { jobId, data } });
      } catch (err) {
        (self as any).postMessage({ type: "error", payload: { msg: "json-parse failed", err } });
      }
      break;
    }
  }
};


